package work.comeback.omo.controller.listener;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import work.comeback.omo.dao.user.IUser;
import work.comeback.omo.dao.user.imp.UserImpl;
import work.comeback.omo.model.user.UserBean;
import work.comeback.omo.util.common.AuthUtils;
import work.comeback.omo.util.configuration.Application;
import work.comeback.omo.util.configuration.model.AppConfig;
import work.comeback.omo.util.configuration.model.ConfigOptions;
import work.comeback.omo.util.configuration.service.DatabaseService;

import java.sql.Connection;
import java.time.LocalDateTime;

public class AppSetupListener implements ServletContextListener {
    private static final Application application = Application.getInstance();
    private static final Logger logger = LoggerFactory.getLogger(AppSetupListener.class);

    private ServletContext context;
    private String serverLocal;
    private Connection connection;
    private ConfigOptions configOptions;


    private String getServerURL() {
        String contextPath = this.context.getContextPath();
        AppConfig appConfig = application.getAppConfig();

        // load config.
        this.configOptions = appConfig.getConfigOptions();

        String port = this.configOptions.getAppPort();
        String address = this.configOptions.getAppAddress();

        return String.format("http://%s:%s%s", address, port, contextPath);
    }

    private boolean startBefore() {
        this.connection = application.getConnection();
        this.serverLocal = this.getServerURL();

        boolean isConnected = this.connection != null;

        if (isConnected) {
            this.createAdminUser();
            return true;
        }
        return false;
    }

    private void startAfter() {
        logger.info("Server is run -> {}", serverLocal);

        context.setAttribute("appConfig", configOptions);
        context.setAttribute("appTitle", configOptions.getAppTitle());
        context.setAttribute("appEmail", configOptions.getAdminEmail());

        context.setAttribute("serverLocal", serverLocal);
        context.setAttribute("serverDate", LocalDateTime.now());

        context.setAttribute("serverApplication", application);
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        this.context = sce.getServletContext();

        boolean isStarted = this.startBefore();

        if (isStarted) {
            this.startAfter();
        }
    }

    private void createAdminUser() {
        IUser userServiceImpl = new UserImpl(this.connection);

        UserBean existingAdmin = userServiceImpl.findUserByUsername("admin");
        if (existingAdmin == null) {
            UserBean admin = new UserBean();
            String pwd = configOptions.getAdminPassword();
            String ePwd = AuthUtils.encryptPassword(pwd);

            admin.setRole("admin");
            admin.setUsername("admin");
            admin.setPassword(ePwd);
            admin.setCreatedAt(LocalDateTime.now());
            admin.setUpdatedAt(LocalDateTime.now());

            userServiceImpl.createUser(admin);
            logger.info("The default GM account is created successfully!");
        } else {
            logger.info("GM already exists, skip initialization!");
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        DatabaseService dbServer = application.getDatabaseService();

        if (dbServer.close(connection)) {
            logger.info("Server is safe shutdown!");
        }
    }
}
